home *** CD-ROM | disk | FTP | other *** search
/ Scene 96 / Scene 96 International Edition (Zyklop Software) (Disc 2) (1997).iso / misc / coding / midas060 / src / winwave.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-01-16  |  28.2 KB  |  1,035 lines

  1. /*      WinWave.c
  2.  *
  3.  * Windows Wave Sound Devicee
  4.  *
  5.  * $Id: winwave.c,v 1.8 1997/01/16 18:41:59 pekangas Exp $
  6.  *
  7.  * Copyright 1996,1997 Housemarque Inc.
  8.  *
  9.  * This file is part of the MIDAS Sound System, and may only be
  10.  * used, modified and distributed under the terms of the MIDAS
  11.  * Sound System license, LICENSE.TXT. By continuing to use,
  12.  * modify or distribute this file you indicate that you have
  13.  * read the license and understand and accept it fully.
  14. */
  15.  
  16. #include <windows.h>
  17. #include <mmsystem.h>
  18. #include <stdio.h>
  19.  
  20. #include "lang.h"
  21. #include "mtypes.h"
  22. #include "errors.h"
  23. #include "mglobals.h"
  24. #include "sdevice.h"
  25. #include "mmem.h"
  26. #include "dsm.h"
  27.  
  28. RCSID(char const *winwave_rcsid = "$Id: winwave.c,v 1.8 1997/01/16 18:41:59 pekangas Exp $";)
  29.  
  30. //#define DUMPBUFFER
  31.  
  32. #define WINWVERSION 1.00
  33. #define WINWVERSTR "1.00"
  34.  
  35.  
  36. /* Maximum number of buffer blocks: (FIXME) */
  37. #define MAXBUFBLOCKS 32
  38.  
  39. /* Number of bits of accuracy in mixing for 8-bit output: */
  40. #define MIX8BITS 12
  41.  
  42.  
  43.  
  44.  
  45. /* Sound Device information */
  46.  
  47.     /* Sound Card names: */
  48. static char     *winwCardName = "Windows Wave output";
  49.  
  50.  
  51.  
  52. /* Sound Device internal static variables */
  53. static unsigned mixRate, outputMode;
  54. static unsigned bufferLen, numBlocks, blockLen;
  55. static unsigned mixElemSize;
  56.  
  57. static unsigned amplification;
  58. static unsigned updateMix;              /* number of elements to mix between
  59.                                            two updates */
  60. static unsigned mixLeft;                /* number of elements to mix before
  61.                                            next update */
  62.  
  63.  
  64. static HWAVEOUT waveHandle;
  65. static HANDLE   blockHandles[MAXBUFBLOCKS];
  66. static uchar    *blocks[MAXBUFBLOCKS];
  67. static HANDLE   blockHeaderHandles[MAXBUFBLOCKS];
  68. static WAVEHDR  *blockHeaders[MAXBUFBLOCKS];
  69. static int      blockPrepared[MAXBUFBLOCKS];
  70.  
  71. static unsigned blockNum;               /* current mixing block number */
  72. static unsigned blockPos;               /* mixing position inside block */
  73.  
  74. static uchar    *ppTable;               /* post-processing table for 8-bit
  75.                                            output */
  76.  
  77. #ifdef DUMPBUFFER
  78. static FILE     *buff;
  79. #endif
  80.  
  81.  
  82. /****************************************************************************\
  83. *       enum winwFunctIDs
  84. *       -----------------
  85. * Description:  ID numbers for Windows Wave Sound Device functions
  86. \****************************************************************************/
  87.  
  88. enum winwFunctIDs
  89. {
  90.     ID_winwDetect = ID_winw,
  91.     ID_winwInit,
  92.     ID_winwClose,
  93.     ID_winwGetMode,
  94.     ID_winwOpenChannels,
  95.     ID_winwSetAmplification,
  96.     ID_winwGetAmplification,
  97.     ID_winwSetUpdRate,
  98.     ID_winwStartPlay,
  99.     ID_winwPlay
  100. };
  101.  
  102.  
  103.  
  104. /* Local prototypes: */
  105. int CALLING winwSetAmplification(unsigned _amplification);
  106. int CALLING winwGetAmplification(unsigned *_amplification);
  107. int CALLING winwSetUpdRate(unsigned updRate);
  108.  
  109.  
  110.  
  111.  
  112.  
  113. /****************************************************************************\
  114. *
  115. * Function:     static int winwError(MMRESULT error)
  116. *
  117. * Description:  Converts a Windows multimedia system error code to MIDAS
  118. *               error code
  119. *
  120. * Input:        MMRESULT error          Windows multimedia system error code
  121. *
  122. * Returns:      MIDAS error code
  123. *
  124. \****************************************************************************/
  125.  
  126. static int winwError(MMRESULT error)
  127. {
  128.     switch ( error )
  129.     {
  130.         case MMSYSERR_NOERROR:
  131.             return OK;
  132.         case MMSYSERR_ERROR:
  133.             return errUndefined;
  134.         case MMSYSERR_BADDEVICEID:
  135.         case MMSYSERR_INVALHANDLE:
  136.         case MMSYSERR_NOTENABLED:
  137.             return errInvalidDevice;
  138.         case MMSYSERR_ALLOCATED:
  139.         case MMSYSERR_HANDLEBUSY:
  140.             return errDeviceBusy;
  141.         case MMSYSERR_NODRIVER:
  142.             return errDeviceNotAvailable;
  143.         case MMSYSERR_NOMEM:
  144.             return errOutOfMemory;
  145.         case MMSYSERR_NOTSUPPORTED:
  146.             return errUnsupported;
  147.         case MMSYSERR_INVALFLAG:
  148.         case MMSYSERR_INVALPARAM:
  149.             return errInvalidArguments;
  150.         case WAVERR_BADFORMAT:
  151.             return errBadMode;
  152.         case WAVERR_STILLPLAYING:
  153.             return errDeviceBusy;
  154.         case WAVERR_UNPREPARED:
  155.             return errInvalidArguments;
  156.         case WAVERR_SYNC:
  157.             return errInvalidDevice;
  158.     }
  159.  
  160.     return errUndefined;
  161. }
  162.  
  163.     /* Error code passing macros for multimedia system errors - similar to
  164.        PASSERROR in errors.h: */
  165.  
  166. #ifdef DEBUG
  167.     #define PASSWINERR(error_, functID) { error = winwError(error_); \
  168.         errAdd(winwError(error_), functID); return error; }
  169. #else
  170.     #define PASSWINERR(error_, functID) return winwError(error_);
  171. #endif
  172.  
  173.  
  174.  
  175.  
  176. /****************************************************************************\
  177. *
  178. * Function:     static unsigned CALLING (*postProc)(unsigned numElements,
  179. *                   uchar *bufStart, unsigned mixPos, unsigned *mixBuffer,
  180. *                   uchar *ppTable);
  181. *
  182. * Description:  Pointer to the actual post-processing routine. Takes
  183. *               DSM output elements from dsmMixBuffer and writes them to
  184. *               output buffer at *bufStart in a format suitable for the Sound
  185. *               Device.
  186. *
  187. * Input:        unsigned numElements    number of elements to process
  188. *                                       (guaranteed to be even)
  189. *               uchar *bufStart         pointer to start of output buffer
  190. *               unsigned mixPos         mixing position in output buffer
  191. *               unsigned *mixBuffer     source mixing buffer
  192. *               uchar *ppTable          pointer to post-processing table
  193. *
  194. * Returns:      New mixing position in output buffer. Can not fail.
  195. *
  196. \****************************************************************************/
  197.  
  198. static unsigned CALLING (*postProc)(unsigned numElements, uchar *bufStart,
  199.     unsigned mixPos, unsigned *mixBuffer, uchar *ppTable);
  200.  
  201.  
  202.  
  203.  
  204. /****************************************************************************\
  205. *
  206. * Function:     unsigned pp16Mono();
  207. *
  208. * Description:  16-bit mono post-processing routine
  209. *
  210. \****************************************************************************/
  211.  
  212. unsigned CALLING pp16Mono(unsigned numElements, uchar *bufStart,
  213.     unsigned mixPos, unsigned *mixBuffer, uchar *ppTable);
  214.  
  215.  
  216.  
  217.  
  218. /****************************************************************************\
  219. *
  220. * Function:     unsigned pp8Mono();
  221. *
  222. * Description:  8-bit mono post-processing routine
  223. *
  224. \****************************************************************************/
  225.  
  226. unsigned CALLING pp8Mono(unsigned numElements, uchar *bufStart,
  227.     unsigned mixPos, unsigned *mixBuffer, uchar *ppTable);
  228.  
  229.  
  230.  
  231.  
  232. /****************************************************************************\
  233. *
  234. * Function:     unsigned pp16Stereo();
  235. *
  236. * Description:  16-bit stereo post-processing routine
  237. *
  238. \****************************************************************************/
  239.  
  240. unsigned CALLING pp16Stereo(unsigned numElements, uchar *bufStart,
  241.     unsigned mixPos, unsigned *mixBuffer, uchar *ppTable);
  242.  
  243.  
  244.  
  245.  
  246. /****************************************************************************\
  247. *
  248. * Function:     unsigned pp8Stereo();
  249. *
  250. * Description:  8-bit stereo post-processing routine
  251. *
  252. \****************************************************************************/
  253.  
  254. unsigned CALLING pp8Stereo(unsigned numElements, uchar *bufStart,
  255.     unsigned mixPos, unsigned *mixBuffer, uchar *ppTable);
  256.  
  257.  
  258.  
  259.  
  260.  
  261.  
  262.  
  263.  
  264.  
  265. /****************************************************************************\
  266. *
  267. * Function:     int winwDetect(int *result)
  268. *
  269. * Description:  Detects a Windows Wave Sound Device
  270. *
  271. * Input:        int *result             pointer to detection result
  272. *
  273. * Returns:      MIDAS error code. Detection result (1 if detected, 0 if not)
  274. *               is written to *result.
  275. *
  276. \****************************************************************************/
  277.  
  278. int CALLING winwDetect(int *result)
  279. {
  280.     /* Check that we have at least one wave output device: */
  281.     if ( waveOutGetNumDevs() < 1 )
  282.         *result = 0;
  283.     else
  284.         *result = 1;
  285.  
  286.     return OK;
  287. }
  288.  
  289.  
  290.  
  291.  
  292. /****************************************************************************\
  293. *
  294. * Function:     int winwInit(unsigned mixRate, unsigned mode)
  295. *
  296. * Description:  Initializes Windows Wave Sound Device
  297. *
  298. * Input:        unsigned mixRate        mixing rate in Hz
  299. *               unsigned mode           output mode
  300. *
  301. * Returns:      MIDAS error code
  302. *
  303. \****************************************************************************/
  304.  
  305. int CALLING winwInit(unsigned _mixRate, unsigned mode)
  306. {
  307.     unsigned    i;
  308.     MMRESULT    mmError;
  309.     int         error;
  310.     WAVEHDR     *header;
  311.     WAVEFORMATEX format;
  312.     int         mixMode;
  313.  
  314.     mixRate = _mixRate;
  315.  
  316.     /* Determine the actual output mode: */
  317.     if ( mode & sdMono )
  318.         outputMode = sdMono;
  319.     else
  320.         outputMode = sdStereo;
  321.     if ( mode & sd8bit )
  322.         outputMode |= sd8bit;
  323.     else
  324.         outputMode |= sd16bit;
  325.  
  326.     /* Calculate one mixing element size: */
  327.     if ( outputMode & sd16bit )
  328.         mixElemSize = 2;
  329.     else
  330.         mixElemSize = 1;
  331.     if ( outputMode & sdStereo )
  332.         mixElemSize <<= 1;
  333.  
  334.     /* Limit number of blocks to MAXBUFBLOCKS: */
  335.     numBlocks = mBufferBlocks;
  336.     if ( numBlocks > MAXBUFBLOCKS )
  337.         numBlocks = MAXBUFBLOCKS;
  338.  
  339.     /* Calculate required buffer block length: (must be a multiple of
  340.        16 bytes) */
  341.     blockLen = mixRate * mixElemSize * mBufferLength / 1000 / numBlocks;
  342.     blockLen = (blockLen + 15) & (~15);
  343.  
  344.     bufferLen = numBlocks * blockLen;
  345.  
  346.     blockNum = blockPos = 0;
  347.  
  348.     /* Set up wave output format structure: */
  349.     format.wFormatTag = WAVE_FORMAT_PCM;
  350.     if ( outputMode & sdStereo )
  351.         format.nChannels = 2;
  352.     else
  353.         format.nChannels = 1;
  354.     format.nSamplesPerSec = mixRate;
  355.     format.nAvgBytesPerSec = mixElemSize * mixRate;
  356.     format.nBlockAlign = mixElemSize;
  357.     if ( outputMode & sd16bit )
  358.         format.wBitsPerSample = 16;
  359.     else
  360.         format.wBitsPerSample = 8;
  361.     format.cbSize = 0;
  362.  
  363.     /* Open wave output device using the format just set up: */
  364.     if ( (mmError = waveOutOpen(&waveHandle, WAVE_MAPPER, &format, 0, 0, 0))
  365.         != 0 )
  366.         PASSWINERR(mmError, ID_winwInit);
  367.  
  368.     /* Allocate and lock memory for all mixing blocks: */
  369.     for ( i = 0; i < numBlocks; i++ )
  370.     {
  371.         /* Allocate global memory for mixing block: */
  372.         if ( (blockHandles[i] = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE,
  373.             blockLen)) == NULL )
  374.         {
  375.             ERROR(errOutOfMemory, ID_winwInit);
  376.             return errOutOfMemory;
  377.         }
  378. /*        printf("Block %i handle %08X\n", i, blockHandles[i]); */
  379.  
  380.         /* Lock mixing block memory: */
  381.         if ( (blocks[i] = GlobalLock(blockHandles[i])) == NULL )
  382.         {
  383.             ERROR(errUnableToLock, ID_winwInit);
  384.             return errUnableToLock;
  385.         }
  386.     }
  387.  
  388.     /* Allocate and lock memory for all mixing block headers: */
  389.     for ( i = 0; i < numBlocks; i++ )
  390.     {
  391.         /* Allocate global memory for mixing block: */
  392.         if ( (blockHeaderHandles[i] = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE,
  393.             sizeof(WAVEHDR))) == NULL )
  394.         {
  395.             ERROR(errOutOfMemory, ID_winwInit);
  396.             return errOutOfMemory;
  397.         }
  398.  
  399.         /* Lock mixing block memory: */
  400.         if ( (header = blockHeaders[i] = GlobalLock(blockHeaderHandles[i]))
  401.             == NULL )
  402.         {
  403.             ERROR(errUnableToLock, ID_winwInit);
  404.             return errUnableToLock;
  405.         }
  406.  
  407.         /* Reset wave header fields: */
  408.         header->lpData = blocks[i];
  409.         header->dwBufferLength = blockLen;
  410.         header->dwFlags = WHDR_DONE;        /* mark the block is done */
  411.         header->dwLoops = 0;
  412.  
  413.         /* Block header is not prepared: */
  414.         blockPrepared[i] = 0;
  415.     }
  416.  
  417.     /* Allocate memory for post-processing table if necessary: */
  418.     if ( outputMode & sd8bit )
  419.     {
  420.         /* Allocate memory for 8-bit output mode post-processing table: */
  421.         if ( (error = memAlloc((1 << MIX8BITS), &ppTable)) != OK )
  422.             PASSERROR(ID_winwInit);
  423.     }
  424.     else
  425.         ppTable = NULL;
  426.  
  427.     /* Check correct mixing mode: */
  428.     if ( outputMode & sdStereo )
  429.         mixMode = dsmMixStereo;
  430.     else
  431.         mixMode = dsmMixMono;
  432.  
  433.     /* Initialize Digital Sound Mixer: */
  434.     if ( outputMode & sd16bit )
  435.     {
  436.         if ( (error = dsmInit(mixRate, mixMode, 16)) != OK )
  437.             PASSERROR(ID_winwInit)
  438.     }
  439.     else
  440.     {
  441.         if ( (error = dsmInit(mixRate, mixMode, MIX8BITS)) != OK )
  442.             PASSERROR(ID_winwInit)
  443.     }
  444.  
  445.     /* Set update rate to 50Hz: */
  446.     if ( (error = winwSetUpdRate(5000)) != OK )
  447.         PASSERROR(ID_winwInit)
  448.  
  449.     /* Point postProc() to correct post-processing routine: */
  450.     switch ( outputMode )
  451.     {
  452.         case (sd16bit | sdMono):
  453.             postProc = &pp16Mono;
  454.             break;
  455.  
  456.         case (sd8bit | sdMono):
  457.             postProc = &pp8Mono;
  458.             break;
  459.  
  460.         case (sd16bit | sdStereo):
  461.             postProc = &pp16Stereo;
  462.             break;
  463.  
  464.         case (sd8bit | sdStereo):
  465.             postProc = &pp8Stereo;
  466.             break;
  467.  
  468.         default:
  469.             ERROR(errInvalidArguments, ID_winwInit);
  470.             return errInvalidArguments;
  471.     }
  472.  
  473.     amplification = 64;
  474.  
  475. #ifdef DUMPBUFFER
  476.     buff = fopen("buffer.raw", "wb");
  477. #endif
  478.  
  479.     return OK;
  480. }
  481.  
  482.  
  483.  
  484.  
  485. /****************************************************************************\
  486. *
  487. * Function:     winwClose(void)
  488. *
  489. * Description:  Uninitializes Windows Wave Sound Device
  490. *
  491. * Returns:      MIDAS error code
  492. *
  493. \****************************************************************************/
  494.  
  495. int CALLING winwClose(void)
  496. {
  497.     int         error;
  498.     MMRESULT    mmError;
  499.     unsigned    i;
  500.     int         allDone;
  501.     DWORD       lasterror;
  502.  
  503. #ifdef DUMPBUFFER
  504.     fclose(buff);
  505. #endif
  506.  
  507.     /* Uninitialize Digital Sound Mixer: */
  508.     if ( (error = dsmClose()) != OK )
  509.         PASSERROR(ID_winwClose)
  510.  
  511.     /* Deallocate post-processing table if necessary: */
  512.     if ( outputMode & sd8bit )
  513.     {
  514.         if ( (error = memFree(ppTable)) != OK )
  515.             PASSERROR(ID_winwClose);
  516.     }
  517.  
  518.     /* Reset wave output device, stop playback, and mark all blocks done: */
  519.     if ( (mmError = waveOutReset(waveHandle)) != 0 )
  520.         PASSWINERR(mmError, ID_winwClose);
  521.  
  522.     /* Make sure all blocks are indeed done: */
  523.     while ( 1 )
  524.     {
  525.         allDone = 1;
  526.         for ( i = 0; i < numBlocks; i++ )
  527.         {
  528.             if ( (blockHeaders[i]->dwFlags & WHDR_DONE) == 0 )
  529.                 allDone = 0;
  530.         }
  531.         if ( allDone )
  532.             break;
  533.         Sleep(20);
  534.     }
  535.  
  536.     /* Unprepare all mixing blocks: */
  537.     for ( i = 0; i < numBlocks; i++ )
  538.     {
  539.         if ( blockPrepared[i] )
  540.         {
  541.             if ( (mmError = waveOutUnprepareHeader(waveHandle, blockHeaders[i],
  542.                 sizeof(WAVEHDR))) != 0 )
  543.                 PASSWINERR(mmError, ID_winwClose);
  544.         }
  545.     }
  546.  
  547.     /* Close wave output device: */
  548.     if ( (mmError = waveOutClose(waveHandle)) != 0 )
  549.         PASSWINERR(mmError, ID_winwClose);
  550.  
  551.     /* Unlock and deallocate all mixing blocks: */
  552.     for ( i = 0; i < numBlocks; i++ )
  553.     {
  554. /*        printf("Unlock block %i\n", i); */
  555.         /* Unlock the mixing block handle: */
  556.         if ( (!GlobalUnlock(blockHandles[i])) && ((lasterror = GetLastError())
  557.             != NO_ERROR) )
  558.         {
  559. /*
  560.             printf("GetLastError(): %u, Handle: %08X\n", lasterror,
  561.                 blockHandles[i]);
  562. */
  563.             ERROR(errHeapCorrupted, ID_winwClose);
  564.             return errHeapCorrupted;
  565.         }
  566.  
  567. /*        printf("Free block %i\n", i); */
  568.         /* Deallocate the mixing block: */
  569.         if ( GlobalFree(blockHandles[i]) != NULL )
  570.         {
  571.             ERROR(errHeapCorrupted, ID_winwClose);
  572.             return errHeapCorrupted;
  573.         }
  574.     }
  575.  
  576.     /* Unlock and deallocate all mixing block headers: */
  577.     for ( i = 0; i < numBlocks; i++ )
  578.     {
  579. /*        printf("Unlock header %i\n", i); */
  580.         /* Unlock the mixing block header handle: */
  581.         if ( (!GlobalUnlock(blockHeaderHandles[i])) && (
  582.             GetLastError() != NO_ERROR) )
  583.         {
  584.             ERROR(errHeapCorrupted, ID_winwClose);
  585.             return errHeapCorrupted;
  586.         }
  587.  
  588. /*        printf("Free header %i\n", i); */
  589.         /* Deallocate the mixing block: */
  590.         if ( GlobalFree(blockHeaderHandles[i]) != NULL )
  591.         {
  592.             ERROR(errHeapCorrupted, ID_winwClose);
  593.             return errHeapCorrupted;
  594.         }
  595.     }
  596.  
  597.     return OK;
  598. }
  599.  
  600.  
  601.  
  602.  
  603. /****************************************************************************\
  604. *
  605. * Function:     int winwGetMode(unsigned *mode)
  606. *
  607. * Description:  Reads the current output mode
  608. *
  609. * Input:        unsigned *mode          pointer to output mode
  610. *
  611. * Returns:      MIDAS error code. Output mode is written to *mode.
  612. *
  613. \****************************************************************************/
  614.  
  615. int CALLING winwGetMode(unsigned *mode)
  616. {
  617.     *mode = outputMode;
  618.  
  619.     return OK;
  620. }
  621.  
  622.  
  623.  
  624.  
  625. /****************************************************************************\
  626. *
  627. * Function:     int winwOpenChannels(unsigned channels)
  628. *
  629. * Description:  Opens sound channels for output. Prepares post-processing
  630. *               tables, takes care of default amplification and finally opens
  631. *               DSM channels. Channels can be closed by simply calling
  632. *               dsmCloseChannels().
  633. *
  634. * Input:        unsigned channels       number of channels to open
  635. *
  636. * Returns:      MIDAS error code
  637. *
  638. \****************************************************************************/
  639.  
  640. int CALLING winwOpenChannels(unsigned channels)
  641. {
  642.     int         error;
  643.  
  644.     /* Open DSM channels: */
  645.     if ( (error = dsmOpenChannels(channels)) != OK )
  646.         PASSERROR(ID_winwOpenChannels)
  647.  
  648.     /* Take care of default amplification and calculate new post-processing
  649.        table if necessary: */
  650. /*
  651.     if ( outputMode & sd8bit )
  652.     {
  653. */
  654.         if ( channels < 5 )
  655.             winwSetAmplification(64);
  656.         else
  657.             winwSetAmplification(14*channels);
  658. /*
  659.     }
  660. */
  661.  
  662.     return OK;
  663. }
  664.  
  665.  
  666.  
  667.  
  668. /****************************************************************************\
  669. *
  670. * Function:     void CalcPP8Table(void)
  671. *
  672. * Description:  Calculates a new 8-bit output post-processing table using
  673. *               current amplification level
  674. *
  675. \****************************************************************************/
  676.  
  677. static void CalcPP8Table(void)
  678. {
  679.     uchar       *tbl;
  680.     int         val;
  681.     long        temp;
  682.  
  683.     tbl = ppTable;                      /* tbl points to current table pos */
  684.  
  685.     /* Calculate post-processing table for all possible DSM values:
  686.        (table must be used with unsigned numbers - add (1 << MIX8BITS)/2 to
  687.        DSM output values first) */
  688.     for ( val = -(1 << MIX8BITS)/2; val < (1 << MIX8BITS)/2; val++ )
  689.     {
  690.         /* Calculate 8-bit unsigned output value corresponding to the
  691.            current DSM output value (val), taking amplification into
  692.            account: */
  693.         temp = 128 + ((((long) amplification) * ((long) val) / 64L) >>
  694.             (MIX8BITS-8));
  695.  
  696.         /* Clip the value to fit between 0 and 255 inclusive: */
  697.         if ( temp < 0 )
  698.             temp = 0;
  699.         if ( temp > 255 )
  700.             temp = 255;
  701.  
  702.         /* Write the value to the post-processing table: */
  703.         *(tbl++) = (uchar) temp;
  704.     }
  705. }
  706.  
  707.  
  708.  
  709.  
  710. /****************************************************************************\
  711. *
  712. * Function:     int winwSetAmplification(unsigned amplification)
  713. *
  714. * Description:  Sets the amplification level. Calculates new post-processing
  715. *               tables and calls dsmSetAmplification() as necessary.
  716. *
  717. * Input:        unsigned amplification  amplification value
  718. *
  719. * Returns:      MIDAS error code
  720. *
  721. \****************************************************************************/
  722.  
  723. int CALLING winwSetAmplification(unsigned _amplification)
  724. {
  725.     int         error;
  726.  
  727.     amplification = _amplification;
  728.  
  729.     if ( outputMode & sd8bit )
  730.     {
  731.         /* 8-bit output mode - do not set amplification level using DSM,
  732.            but calculate a new post-processing table instead: */
  733.         CalcPP8Table();
  734.     }
  735.     else
  736.     {
  737.         /* Set amplification level to DSM: */
  738.         if ( (error = dsmSetAmplification(amplification)) != OK )
  739.             PASSERROR(ID_winwSetAmplification)
  740.     }
  741.  
  742.     return OK;
  743. }
  744.  
  745.  
  746.  
  747.  
  748. /****************************************************************************\
  749. *
  750. * Function:     int winwGetAmplification(unsigned *amplification);
  751. *
  752. * Description:  Reads the current amplification level. (DSM doesn't
  753. *               necessarily know the actual amplification level if
  754. *               post-processing takes care of amplification)
  755. *
  756. * Input:        unsigned *amplification   pointer to amplification level
  757. *
  758. * Returns:      MIDAS error code. Amplification level is written to
  759. *               *amplification.
  760. *
  761. \****************************************************************************/
  762.  
  763. int CALLING winwGetAmplification(unsigned *_amplification)
  764. {
  765.     *_amplification = amplification;
  766.  
  767.     return OK;
  768. }
  769.  
  770.  
  771.  
  772.  
  773. /****************************************************************************\
  774. *
  775. * Function:     int winwSetUpdRate(unsigned updRate);
  776. *
  777. * Description:  Sets the channel value update rate (depends on song tempo)
  778. *
  779. * Input:        unsigned updRate        update rate in 100*Hz (eg. 50Hz
  780. *                                       becomes 5000).
  781. *
  782. * Returns:      MIDAS error code
  783. *
  784. \****************************************************************************/
  785.  
  786. int CALLING winwSetUpdRate(unsigned updRate)
  787. {
  788.     /* Calculate number of elements to mix between two updates: (even) */
  789.     mixLeft = updateMix = ((unsigned) ((100L * (ulong) mixRate) /
  790.         ((ulong) updRate)) + 1) & 0xFFFFFFFE;
  791.  
  792.     return OK;
  793. }
  794.  
  795.  
  796.  
  797.  
  798. /****************************************************************************\
  799. *
  800. * Function:     int winwStartPlay(void)
  801. *
  802. * Description:  Prepares for playing - doesn't actually do anything here...
  803. *
  804. * Returns:      MIDAS error code
  805. *
  806. \****************************************************************************/
  807.  
  808. int CALLING winwStartPlay(void)
  809. {
  810.     return OK;
  811. }
  812.  
  813.  
  814.  
  815.  
  816. /****************************************************************************\
  817. *
  818. * Function:     int winwPlay(int *callMP);
  819. *
  820. * Description:  Plays the sound - mixes the correct amount of data with DSM
  821. *               and copies it to wave output buffer with post-processing.
  822. *               Also takes care of sending fully mixed blocks to the wave
  823. *               output device.
  824. *
  825. * Input:        int *callMP             pointer to music player calling flag
  826. *
  827. * Returns:      MIDAS error code. If enough data was mixed for one updating
  828. *               round and music player should be called, 1 is written to
  829. *               *callMP, otherwise 0 is written there. Note that if music
  830. *               player can be called, winwPlay() should be called again
  831. *               with a new check for music playing to ensure the mixing buffer
  832. *               gets filled with new data.
  833. *
  834. \****************************************************************************/
  835.  
  836. int CALLING winwPlay(int *callMP)
  837. {
  838.     int         error;
  839.     MMRESULT    mmError;
  840.     unsigned    blockLeft, numElems;
  841.     unsigned    dsmBufSize;
  842.     unsigned    oldPos;
  843.  
  844.     /* Calculate DSM mixing buffer size in elements: (FIXME) */
  845.     dsmBufSize = dsmMixBufferSize;
  846. #ifdef __32__
  847.     dsmBufSize >>= 2;
  848. #else
  849.     dsmBufSize >>= 1;
  850. #endif
  851.     if ( outputMode & sdStereo )
  852.         dsmBufSize >>= 1;
  853.  
  854.     /* Repeat while we have unused blocks left: */
  855.  
  856.     while ( blockHeaders[blockNum]->dwFlags & WHDR_DONE )
  857.     {
  858.         /* Check if the block is prepared - if so, unprepare it: */
  859.         if ( blockPrepared[blockNum] )
  860.         {
  861.             if ( (mmError = waveOutUnprepareHeader(waveHandle,
  862.                 blockHeaders[blockNum], sizeof(WAVEHDR))) != 0 )
  863.                 PASSWINERR(mmError, ID_winwPlay);
  864.             blockPrepared[blockNum] = 0;
  865.         }
  866.  
  867.         /* Calculate number of bytes of block left: */
  868.         blockLeft = blockLen - blockPos;
  869.  
  870.         /* Calculate number of mixing elements left: */
  871.         numElems = blockLeft / mixElemSize;
  872.  
  873.         /* Check that we won't mix more data than there is to the next
  874.            update: */
  875.         if ( numElems > mixLeft )
  876.             numElems = mixLeft;
  877.  
  878.         /* Check that we won't mix more data than fits to DSM mixing
  879.            buffer: */
  880.         if ( numElems > dsmBufSize )
  881.             numElems = dsmBufSize;
  882.  
  883.         /* Decrease number of elements before next update: */
  884.         mixLeft -= numElems;
  885.  
  886.         /* Mix the data to DSM mixing buffer: */
  887.         if ( (error = dsmMixData(numElems)) != OK )
  888.             PASSERROR(ID_winwPlay)
  889.  
  890.         /* Write the mixed data to output buffer: */
  891.         oldPos = blockPos;
  892.         blockPos = postProc(numElems, blocks[blockNum], blockPos,
  893.             dsmMixBuffer, ppTable);
  894.  
  895. #ifdef DUMPBUFFER
  896.         fwrite(&blocks[blockNum][oldPos], numElems * mixElemSize, 1, buff);
  897. #endif
  898.  
  899.         /* Check if the block is full - if so, write it to the wave output
  900.            device and move to the next one: */
  901.         if ( blockPos >= blockLen )
  902.         {
  903.             blockHeaders[blockNum]->dwFlags = 0;
  904.             /* Reset wave header fields: */
  905.             blockHeaders[blockNum]->lpData = blocks[blockNum];
  906.             blockHeaders[blockNum]->dwBufferLength = blockLen;
  907.             blockHeaders[blockNum]->dwFlags = 0;
  908.             blockHeaders[blockNum]->dwLoops = 0;
  909.  
  910.             /* Prepare block header: */
  911.             if ( (mmError = waveOutPrepareHeader(waveHandle,
  912.                 blockHeaders[blockNum], sizeof(WAVEHDR))) != 0 )
  913.                 PASSWINERR(mmError, ID_winwPlay);
  914.             blockPrepared[blockNum] = 1;
  915.  
  916.             if ( (mmError = waveOutWrite(waveHandle, blockHeaders[blockNum],
  917.                 sizeof(WAVEHDR))) != 0 )
  918.                 PASSWINERR(mmError, ID_winwPlay);
  919.  
  920.             //blockNum = (blockNum++) % numBlocks;
  921.             blockPos = 0;
  922.             blockNum++;
  923.             if ( blockNum >= numBlocks )
  924.                 blockNum = 0;
  925.         }
  926.  
  927.         /* Check if the music player should be called: */
  928.         if ( mixLeft == 0 )
  929.         {
  930.             mixLeft = updateMix;
  931.             *callMP = 1;
  932.             return OK;
  933.         }
  934.     }
  935.  
  936.     /* No more data fits to the mixing blocks - just return without
  937.        update: */
  938.     *callMP = 0;
  939.  
  940.     return OK;
  941. }
  942.  
  943.  
  944.  
  945.  
  946.  
  947.  
  948.     /* WinWave Sound Device structure: */
  949.  
  950. SoundDevice     WinWave = {
  951.     0,                                  /* tempoPoll = 0 */
  952.     sdUseMixRate | sdUseOutputMode | sdUseDSM,  /* configBits */
  953.     0,                                  /* port */
  954.     0,                                  /* IRQ */
  955.     0,                                  /* DMA */
  956.     1,                                  /* cardType */
  957.     1,                                  /* numCardTypes */
  958.     sdMono | sdStereo | sd8bit | sd16bit,       /* modes */
  959.  
  960.     "Windows Wave Sound Device " WINWVERSTR,     /* name */
  961.     &winwCardName,                              /* cardNames */
  962.     0,                                          /* numPortAddresses */
  963.     NULL,                                       /* portAddresses */
  964.  
  965.     &winwDetect,
  966.     &winwInit,
  967.     &winwClose,
  968.     &dsmGetMixRate,
  969.     &winwGetMode,
  970.     &winwOpenChannels,
  971.     &dsmCloseChannels,
  972.     &dsmClearChannels,
  973.     &dsmMute,
  974.     &dsmPause,
  975.     &dsmSetMasterVolume,
  976.     &dsmGetMasterVolume,
  977.     &winwSetAmplification,
  978.     &winwGetAmplification,
  979.     &dsmPlaySound,
  980.     &dsmReleaseSound,
  981.     &dsmStopSound,
  982.     &dsmSetRate,
  983.     &dsmGetRate,
  984.     &dsmSetVolume,
  985.     &dsmGetVolume,
  986.     &dsmSetSample,
  987.     &dsmGetSample,
  988.     &dsmSetPosition,
  989.     &dsmGetPosition,
  990.     &dsmGetDirection,
  991.     &dsmSetPanning,
  992.     &dsmGetPanning,
  993.     &dsmMuteChannel,
  994.     &dsmAddSample,
  995.     &dsmRemoveSample,
  996.     &winwSetUpdRate,
  997.     &winwStartPlay,
  998.     &winwPlay
  999. #ifdef SUPPORTSTREAMS
  1000.     ,
  1001.     &dsmStartStream,
  1002.     &dsmStopStream,
  1003.     &dsmSetLoopCallback,
  1004.     &dsmSetStreamWritePosition
  1005. #endif
  1006. };
  1007.  
  1008.  
  1009. /*
  1010.  * $Log: winwave.c,v $
  1011.  * Revision 1.8  1997/01/16 18:41:59  pekangas
  1012.  * Changed copyright messages to Housemarque
  1013.  *
  1014.  * Revision 1.7  1997/01/16 18:28:40  pekangas
  1015.  * Added pointer to dsmSetStreamWritePosition
  1016.  *
  1017.  * Revision 1.6  1996/07/29 19:33:10  pekangas
  1018.  * Added a proper detection function
  1019.  *
  1020.  * Revision 1.5  1996/07/13 19:56:40  pekangas
  1021.  * Eliminated Visual C warnings
  1022.  *
  1023.  * Revision 1.4  1996/07/08 19:40:32  pekangas
  1024.  * Fixed winwClose() calling convention
  1025.  *
  1026.  * Revision 1.3  1996/05/26 20:57:00  pekangas
  1027.  * Added StartStream and EndStream to WinWave Sound Device structure
  1028.  *
  1029.  * Revision 1.2  1996/05/25 09:32:47  pekangas
  1030.  * Changed to use mBufferLength and mBufferBlocks
  1031.  *
  1032.  * Revision 1.1  1996/05/22 20:49:33  pekangas
  1033.  * Initial revision
  1034.  *
  1035. */